package com.ionehe.group.common.uaa.ex.domain.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.ionehe.group.common.io.Response;
import com.ionehe.group.common.uaa.ex.enums.ErrorMessages;
import com.ionehe.group.common.uaa.ex.model.UaaCustomerFunction;
import com.ionehe.group.common.uaa.ex.model.UaaCustomerSetMeal;
import com.ionehe.group.common.uaa.ex.model.UaaRoleFunction;
import com.ionehe.group.common.uaa.ex.model.UaaSetMeal;
import com.ionehe.group.common.uaa.ex.model.UaaSetMealFunction;
import com.ionehe.group.common.uaa.ex.dto.SetMealDTO;
import com.ionehe.group.common.uaa.ex.dao.CustomerFunctionDao;
import com.ionehe.group.common.uaa.ex.dao.CustomerSetMealDao;
import com.ionehe.group.common.uaa.ex.dao.RoleFunctionDao;
import com.ionehe.group.common.uaa.ex.dao.SetMealDao;
import com.ionehe.group.common.uaa.ex.dao.SetMealFunctionDao;
import com.ionehe.group.common.uaa.ex.domain.service.SetMealWriteService;
import com.ionehe.group.common.uaa.ex.domain.service.UserCacheWriteService;
import com.ionehe.group.common.user.c.sdk.uaa.component.DynamicSecurityMetadataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Copyright (c) 2020 ionehe.com
 * Date: 2020/11/25 0025
 * Time: 10:03
 *
 * @author 2020年 <a href="mailto:a@ionehe.com">秀</a>
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class SetMealWriteServiceImpl implements SetMealWriteService {

    @Autowired
    SetMealDao setMealDao;
    @Autowired
    SetMealFunctionDao setMealFunctionDao;
    @Autowired
    CustomerSetMealDao customerSetMealDao;
    @Resource
    CustomerFunctionDao customerFunctionDao;
    @Resource
    RoleFunctionDao roleFunctionDao;
    @Autowired
    UserCacheWriteService userCacheWriteService;
    @Autowired
    private DynamicSecurityMetadataSource dynamicSecurityMetadataSource;

    @Override
    public Response setMealAddAndUpdate(SetMealDTO setMealDTO) {
        log.info("SetMealServiceWriteImpl[]setMealAddAndUpdate[]start! setMealDTO:{}", setMealDTO);
        if (setMealDTO == null) return Response.no(ErrorMessages.ILLEGAL_PARAMS.toString());

        // 新增套餐
        if (isNew(setMealDTO.getId())) {
            if (checkSetmealName(setMealDTO.getName())) return Response.no("套餐名称重复");
            if (checkSetmealNameLong(setMealDTO.getName())) return Response.no("套餐名称长度太长");

            // 新增套餐
            Long newSeatMealId = newSetMeal(setMealDTO);
            log.info("SetMealServiceWriteImpl[]setMealAdd[]success!");

            // 更新套餐权限关系表
            newSetMealFunction(setMealDTO.getFunctionIdList(), newSeatMealId);

            return Response.yes("添加套餐成功");
        }

        // 更新套餐
        Long setMealId = setMealDTO.getId();
        UaaSetMeal setMeal = setMealDao.selectByMealId(setMealId);
        if (setMeal == null) return Response.no("套餐已不存在");

        // 套餐名称是否重复
        if (!setMeal.getName().equals(setMealDTO.getName()) && checkSetmealName(setMealDTO.getName())) {
            return Response.no("套餐名称重复");
        }
        // 套餐长度是否超标
        if (checkSetmealNameLong(setMealDTO.getName())) return Response.no("套餐名称长度太长");
        updateSetMeal(setMealDTO, setMeal);

        // 分类操作
        List<Long> newFunList = setMealDTO.getFunctionIdList();
        List<Long> oldFunList = setMealFunctionDao.selectFunctionIdsBysetMealId(setMealId);
        List<Long> addFunList = new ArrayList<>();
        List<Long> deleteFunList = new ArrayList<>();
        // 新增功能集合
        newFunList.stream().filter(funId -> !(oldFunList.contains(funId))).forEach(addFunList::add);
        // 删除功能集合
        oldFunList.stream().filter(funId -> !(newFunList.contains(funId))).forEach(deleteFunList::add);

        // 添加新增的功能
        newSetMealFunction(setMealDTO, addFunList);
        log.info("SetMealServiceWriteImpl[]setMealFunctionAdd[]success!");

        // 正在使用该套餐的客户，自动进行套餐升级
        autoUpgrade(setMealId, addFunList);

        // 删除编辑要取消的功能
        if (CollUtil.isNotEmpty(deleteFunList)) {
            Example example = new Example(UaaSetMealFunction.class);
            example.createCriteria().andEqualTo("setMealId", setMealDTO.getId())
                    .andIn("functionId", deleteFunList);

            setMealFunctionDao.deleteByExample(example);
        }

        // 正在使用该套餐的客户，自动降级
        autoDegrade(setMealId, deleteFunList);

        log.info("SetMealServiceWriteImpl[]setMealFunctionDelete[[]success!");

        userCacheWriteService.delResourceModuleCache();
        dynamicSecurityMetadataSource.clearDataSource();

        return Response.yes("编辑套餐成功！");
    }

    private void newSetMealFunction(SetMealDTO setMealDTO, List<Long> addFunList) {
        if (CollUtil.isNotEmpty(addFunList)) {
            List<UaaSetMealFunction> addSetMealFunctionList = addFunList.stream().map(funId -> {
                UaaSetMealFunction setMealFunction = new UaaSetMealFunction();
                setMealFunction.setSetMealId(setMealDTO.getId());
                setMealFunction.setCreateTime(new Date());
                setMealFunction.setFunctionId(funId);
                return setMealFunction;
            }).collect(Collectors.toList());
            setMealFunctionDao.insertList(addSetMealFunctionList);
        }
    }

    private void updateSetMeal(SetMealDTO setMealDTO, UaaSetMeal setMeal) {
        setMeal.setName(setMealDTO.getName());
        setMeal.setDuration(setMealDTO.getDuration());
        setMeal.setUpdateTime(new Date());
        setMealDao.updateSetmeal(setMeal);
    }

    private boolean isNew(Long setMealId) {
        return setMealId == null;
    }

    @Override
    public Response setMealDelete(Long setMealId) {
//        判断套餐id是否为空
        if (setMealId == null) {
            return Response.no("套餐id为空");
        }

        Integer i1 = setMealDao.setMealDelete(setMealId);
//                    删除套餐与功能的关系
        Integer i2 = setMealFunctionDao.deleteBySetMealId(setMealId);
        return Response.yes();
    }

    @Override
    public Response deleteJudge(Long setMealId) {
        //        判断该套餐是否有客户在使用()
        List<UaaCustomerSetMeal> customerSetMeals = customerSetMealDao.selectCustomerInfoBySetmealId(setMealId);
        if (CollUtil.isNotEmpty(customerSetMeals)) {
//            判断该用户使用的套餐是否过期
            for (UaaCustomerSetMeal customerSetMeal : customerSetMeals) {
                if (customerSetMeal.getTimeout().after(new Date())) {
                    return Response.yes(false);
                } else {
                    return Response.yes();
                }
            }
        }
        return Response.yes();
    }


    /**
     * 判断套餐名称是否重复
     *
     * @param name
     */
    private boolean checkSetmealName(String name) {
        List<UaaSetMeal> setMeals = setMealDao.selectList();
        for (UaaSetMeal setMeal : setMeals) {
            if (Objects.equals(setMeal.getName(), name)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断套餐名称长度
     *
     * @param name
     * @return
     */
    private boolean checkSetmealNameLong(String name) {
        if (name.length() > 16) {
            return true;
        }
        return false;
    }

    /**
     * 自动降级
     *
     * @param setMealId  套餐id
     * @param deleteList functionId集合
     */
    private void autoDegrade(Long setMealId, List<Long> deleteList) {
        if (setMealId == null || CollUtil.isEmpty(deleteList)) {
            return;
        }

        // 下架超级管理员权限
        List<UaaCustomerSetMeal> customerSetMealList = customerSetMealDao.selectCustomerInfoBySetmealId(setMealId);
        if (CollUtil.isNotEmpty(customerSetMealList)) {
            List<Long> cidList = customerSetMealList.stream().map(UaaCustomerSetMeal::getCustomerId).distinct().collect(Collectors.toList());
            cidList.forEach(cid -> {
                Example e = new Example(UaaCustomerFunction.class);
                e.createCriteria().andEqualTo("customerId", cid)
                        .andIn("functionId", deleteList);
                customerFunctionDao.deleteByExample(e);
            });
        }

        // 下架涉及的角色权限
        Example e = new Example(UaaRoleFunction.class);
        e.createCriteria()
                .andIn("functionId", deleteList);
        roleFunctionDao.deleteByExample(e);
    }

    /**
     * 自动升级
     *
     * @param setMealId 套餐id
     * @param addList   functionId集合
     */
    private void autoUpgrade(Long setMealId, List<Long> addList) {
        if (setMealId == null || CollUtil.isEmpty(addList)) {
            return;
        }

        List<UaaCustomerSetMeal> customerSetMealList = customerSetMealDao.selectCustomerInfoBySetmealId(setMealId);
        List<Long> cidList = customerSetMealList.stream().map(UaaCustomerSetMeal::getCustomerId).distinct().collect(Collectors.toList());

        List<UaaCustomerFunction> upgrade = new ArrayList<>();
        cidList.forEach(cid -> {
            List<UaaCustomerFunction> cfList = addList.stream().map(addId -> {
                UaaCustomerFunction cf = new UaaCustomerFunction();
                cf.setCreateTime(new Date());
                cf.setCustomerId(cid);
                cf.setFunctionId(addId);
                return cf;
            }).collect(Collectors.toList());

            upgrade.addAll(cfList);
        });

        customerFunctionDao.insertList(upgrade);
    }

    private void newSetMealFunction(List<Long> functionList, Long newSeatMealId) {
        if (!functionList.contains(2L)) functionList.add(2L);
        ArrayList<UaaSetMealFunction> setMealFunctions = new ArrayList<>();
        for (Long id : functionList) {
            UaaSetMealFunction setMealFunction = new UaaSetMealFunction();
            setMealFunction.setSetMealId(newSeatMealId);
            setMealFunction.setCreateTime(new Date());
            setMealFunction.setFunctionId(id);
            setMealFunctions.add(setMealFunction);
        }
        if (CollUtil.isNotEmpty(setMealFunctions)) {
            setMealFunctionDao.insertList(setMealFunctions);
        }
        log.info("SetMealServiceWriteImpl[]setMealFunctionAdd[]success!");
    }

    private Long newSetMeal(SetMealDTO setMealDTO) {
        UaaSetMeal newSetMeal = new UaaSetMeal();
        Date createDate = new Date();
        newSetMeal.setName(setMealDTO.getName());
        newSetMeal.setDuration(setMealDTO.getDuration());
        newSetMeal.setCreateTime(createDate);
        setMealDao.insertSetmeal(newSetMeal);
        return newSetMeal.getId();
    }
}
